package com.vincent.template.service.logic.impl;

import com.google.common.collect.Lists;
import com.vincent.template.commons.exception.Vct520Exception;
import com.vincent.template.domain.SysUserPo;
import com.vincent.template.dto.sys.user.UserCancelDto;
import com.vincent.template.dto.sys.user.UserInfoDto;
import com.vincent.template.dto.sys.user.UserPwdResetDto;
import com.vincent.template.dto.sys.user.UserRegisterDto;
import com.vincent.template.dto.sys.user.UserUpdateDto;
import com.vincent.template.repository.SysBindUserGroupUserRepository;
import com.vincent.template.repository.SysBindUserRoleRepository;
import com.vincent.template.repository.SysRoleRepository;
import com.vincent.template.repository.SysUserRepository;
import com.vincent.template.service.logic.UserService;
import com.vincent.template.service.security.UserRoleAuthService;
import com.vincent.template.utils.DateUtil;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Vincent Wang
 * @date 2021/3/24 22:30
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private SysUserRepository userRepository;
    @Autowired
    private SysRoleRepository roleRepository;
    @Autowired
    private SysBindUserGroupUserRepository bindUserGroupUserRepository;
    @Autowired
    private SysBindUserRoleRepository bindUserRoleRepository;
    @Autowired
    private UserRoleAuthService userRoleAuthService;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public List<UserInfoDto> findUsers() {
        List<SysUserPo> users = userRepository.findAll();
        if (CollectionUtils.isEmpty(users)) {
            return Lists.newArrayList();
        }
        return users.stream().map(user -> {
            UserInfoDto userInfo = new UserInfoDto();
            BeanUtils.copyProperties(user, userInfo);
            return userInfo;
        }).collect(Collectors.toList());
    }

    @Override
    public UserInfoDto findUserById(String id) {
        SysUserPo user = userRepository.findById(id).orElse(null);
        if (user == null) {
            return null;
        }
        UserInfoDto userInfo = new UserInfoDto();
        BeanUtils.copyProperties(user, userInfo);
        return userInfo;
    }

    @Override
    public String register(UserRegisterDto registerDto) {
        String username = registerDto.getUsername();
        SysUserPo user = userRepository.findByUsernameAndDeletedFalse(username);
        Vct520Exception.throwIfTrue(user != null, "用户名已存在：" + username);
        userRepository.deleteByUsername(username);
        user = new SysUserPo();
        BeanUtils.copyProperties(registerDto, user);
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        return userRepository.save(user).getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean resetPwd(String id, UserPwdResetDto pwdResetDto) {
        SysUserPo user = userRepository.findById(id).orElse(null);
        Vct520Exception.throwIfEmpty(user, "用户不存在");
        Vct520Exception.throwIfTrue(!passwordEncoder
                .matches(pwdResetDto.getOldPwd(), user.getPassword()), "旧密码输入错误");
        user.setPassword(passwordEncoder.encode(pwdResetDto.getNewPwd()));
        userRepository.save(user);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateInfo(String id, UserUpdateDto updateDto) {
        SysUserPo user = userRepository.findById(id).orElse(null);
        Vct520Exception.throwIfEmpty(user, "用户不存在");
        BeanUtils.copyProperties(updateDto, user, "birthday");
        user.setBirthday(DateUtil.parseToDate(updateDto.getBirthday()));
        userRepository.save(user);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean selfCancel(UserCancelDto cancelDto) {
        String userId = cancelDto.getId();
        SysUserPo user = userRepository.findById(userId).orElse(null);
        Vct520Exception.throwIfEmpty(user, "用户不存在");
        Vct520Exception.throwIfTrue(!passwordEncoder
                .matches(cancelDto.getPassword(), user.getPassword()), "密码输入错误");
        checkUnremovableRole(userId);
        user.setDeleted(true);
        userRepository.save(user);
        bindUserGroupUserRepository.deleteByUserId(userId);
        bindUserRoleRepository.deleteByUserId(userId);
        // 注销账号后，需要退出当前登录
        SecurityContextHolder.getContext().getAuthentication().setAuthenticated(false);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean adminCancel(String id) {
        SysUserPo user = userRepository.findById(id).orElse(null);
        Vct520Exception.throwIfEmpty(user, "用户不存在");
        checkUnremovableRole(id);
        user.setDeleted(true);
        userRepository.save(user);
        bindUserGroupUserRepository.deleteByUserId(id);
        bindUserRoleRepository.deleteByUserId(id);
        return true;
    }

    private void checkUnremovableRole(String userId) {
        List<String> roleCodes = userRoleAuthService.findRolesAndAuths(userId).getLeft();
        List<String> userUnremovableRoles  = roleRepository.findUserUnremovableRoles(roleCodes);
        Vct520Exception.throwIfTrue(CollectionUtils.isNotEmpty(userUnremovableRoles),
                "拥有角色" + userUnremovableRoles + "的用户不可移除");
    }
}
